package com.tao.mvpbaselibrary.lib_http.retrofit;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okio.Buffer;
import retrofit2.Converter;
import retrofit2.Retrofit;


public class GsonExposeConverterFactory extends Converter.Factory {
    private  static  final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
    private static  final Charset UTF_8 = Charset.forName("UTF-8");
    private final Gson gson;

    private GsonExposeConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }

    public static GsonExposeConverterFactory create() {
        return create(new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create());
    }

    public static GsonExposeConverterFactory create(Gson gson) {
        return new GsonExposeConverterFactory(gson);
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonResponseBodyConverter<>(gson, adapter);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonRequestBodyConverter<>(gson, adapter);
    }

    final class CustomGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {

        private final Gson gson;
        private final TypeAdapter<T> adapter;

        CustomGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
            this.gson = gson;
            this.adapter = adapter;
        }

        @Override
        public RequestBody convert(T value) throws IOException {
            Buffer buffer = new Buffer();
            Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
            JsonWriter jsonWriter = gson.newJsonWriter(writer);
            adapter.write(jsonWriter, value);
            jsonWriter.close();
            return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
        }
    }

      static class CustomGsonResponseBodyConverter<T> implements Converter<ResponseBody,T> {

        private final Gson gson;
        private final TypeAdapter<T> adapter;

        CustomGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
            this.gson = gson;
            this.adapter = adapter;
        }


        @Override
        public T convert(ResponseBody value) throws IOException {
            JsonReader jsonReader = gson.newJsonReader(value.charStream());
            try {
                T result = adapter.read(jsonReader);
                if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
                    throw new JsonIOException("JSON document was not fully consumed.");
                }
                return result;
            } finally {
                value.close();
            }
        }

//        @Override
//        public ResponseBody convert(T value) throws IOException {
//            Buffer buffer = new Buffer();
//            Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
//            JsonWriter jsonWriter = gson.newJsonWriter(writer);
//            adapter.write(jsonWriter, value);
//            jsonWriter.close();
//            return ResponseBody.create(MEDIA_TYPE, buffer.readByteString());
//        }

//        @Override
//        public T convert(ResponseBody value) throws IOException {
//            String response = value.string();
//            BaseResponse baseResponse = gson.fromJson(response, BaseResponse.class);
//            //核心代码:  判断 status 是否是后台定义的正常值
//            if (baseResponse.isCodeInvalid()) {
//                value.close();
//                throw new ApiException(baseResponse.getStatus(), baseResponse.getMessage());
//            }
//
//            MediaType contentType = value.contentType();
//            Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
//            InputStream inputStream = new ByteArrayInputStream(response.getBytes());
//            Reader reader = new InputStreamReader(inputStream, charset);
//            JsonReader jsonReader = gson.newJsonReader(reader);
//
//            try {
//                return adapter.read(jsonReader);
//            } finally {
//                value.close();
//            }
//        }
    }
}
